#include "floorserial.h"
#include "qdebug.h"
#include "logger.h"
#include "source/configmanager.h"
#include "source/md5.h"

#include <qrandom.h>

FloorSerial::FloorSerial(QObject *parent)
    : QObject(parent),
    m_mainlight(ParamValue.getParameter<float>("floor","mainlight")),
    m_leftlight(ParamValue.getParameter<float>("floor","leftlight")),
    m_rightlight(ParamValue.getParameter<float>("floor","rightlight")),
    m_fan1(ParamValue.getParameter<float>("floor","fan1")),
    m_fan2(ParamValue.getParameter<float>("floor","fan2"))
{
    serial_ = nullptr ;

    initSetting();
    connect(&ParamValue,&ConfigManager::valueTableLoad,this, &FloorSerial::initSetting);
    connect(this,&FloorSerial::openSerialFinish,this,&FloorSerial::valueTableLoad);
    connect(&ConfigManager::getInstance(), &ConfigManager::valueTableLoad, this, &FloorSerial::valueTableLoad);
    searchSerialPorts();

    //QMetaObject::invokeMethod(this, "openPort", Q_ARG(QString, "/dev/ttyS1"), Q_ARG(int, 9600));


}

FloorSerial::~FloorSerial() {
    delete verifiTimer;
    verifiTimer = nullptr;
    closePort();
}

QStringList FloorSerial::searchSerialPorts()
{
    LogDebug << "Attempting searchSerialPorts";
    m_serialPortList.clear();
    const auto ports = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &port : ports) {
        m_serialPortList.append(port.portName());
    }
    for (const QSerialPortInfo &serialPortInfo : ports) {
        qDebug() << "Port:" << serialPortInfo.portName();
        qDebug() << "Description:" << serialPortInfo.description();
        qDebug() << "Manufacturer:" << serialPortInfo.manufacturer();
        qDebug() << "Serial number:" << serialPortInfo.serialNumber();
        qDebug() << "System location:" << serialPortInfo.systemLocation();
        qDebug() << "-----------------------------------";
    }
    return m_serialPortList;
}

void FloorSerial::startVerifi()
{
    verifiTimer = new QTimer;
    connect(verifiTimer, &QTimer::timeout, this, &FloorSerial::startVerifiSlot);
    verifiTimer->start(10000);

    holdTimer = new QTimer;
    connect(holdTimer, &QTimer::timeout, this, &FloorSerial::holdsentTimer);
    holdTimer->start(1000);
    LogDebug << "Start to startVerifiSlot";
}

void FloorSerial::setmainlight(float mainlight)
{
    if(mainlight != m_mainlight)
    {
        m_mainlight = mainlight;
        LogDebug << "set m_mainlight :" << m_mainlight;
        ParamValue.setParameter("floor","mainlight",m_mainlight);
        QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 1), Q_ARG(float, mainlight));
        QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 4), Q_ARG(float, mainlight));
        emit mainlightChanged();
    }
}

void FloorSerial::setleftlight(float leftlight)
{
    if(leftlight != m_leftlight)
    {
        m_leftlight = leftlight;
        LogDebug << "set m_leftlight :" << m_leftlight;
        ParamValue.setParameter("floor","leftlight",m_leftlight);
        QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 2), Q_ARG(float, leftlight));
        emit leftlightChanged();
    }
}

void FloorSerial::setrightlight(float rightlight)
{
    if(rightlight != m_rightlight)
    {
        m_rightlight = rightlight;
        LogDebug << "set m_rightlight :" << m_rightlight;
        ParamValue.setParameter("floor","rightlight",m_rightlight);
        QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 3), Q_ARG(float, rightlight));
        emit rightlightChanged();
    }
}

void FloorSerial::setfan1(float fan1)
{
    if(fan1 != m_fan1)
    {
        m_fan1 = fan1;
        ParamValue.setParameter("floor","fan1",m_fan1);
        QMetaObject::invokeMethod(this, "controlFan", Q_ARG(int, 1), Q_ARG(float, fan1));
        emit fan1Changed();
    }
}

void FloorSerial::setfan2(float fan2)
{
    if(fan2 != m_fan2)
    {
        m_fan2 = fan2;
        ParamValue.setParameter("floor","fan2",m_fan2);
        QMetaObject::invokeMethod(this, "controlFan", Q_ARG(int, 2), Q_ARG(float, fan2));
        emit fan2Changed();
    }
}

bool FloorSerial::  verifiMD5()
{
    uint8_t *MD5Bytes = masterVerifi(Last_randomBytes,16);
    if (revMD5.size() < 16) {
        qDebug() << "Error: revMD5 does not have at least 16 bytes.";
        return false;
    }

    // qDebug() << "revMD5 first 16 bytes:";
    // for (int i = 0; i < 16; ++i) {
    //     qDebug() << QString::number(static_cast<uint8_t>(revMD5[i]), 16).rightJustified(2, '0').toUpper();
    // }

    // // 打印 MD5Bytes 的前16位
    // qDebug() << "MD5Bytes first 16 bytes:";
    // for (int i = 0; i < 16; ++i) {
    //     qDebug() << QString::number(MD5Bytes[i], 16).rightJustified(2, '0').toUpper();
    // }

    bool isEqual = true;
    for (int i = 0; i < 16; ++i) {
        if (static_cast<uint8_t>(revMD5[i]) != MD5Bytes[i]) {
            isEqual = false;
            break;
        }
    }
    revMD5.clear();
    // 输出比较结果
    if (isEqual) {
        return true;
    } else {
        return false;
    }

}

void FloorSerial::holdsentTimer()
{
    holdserial();
}

void FloorSerial::startVerifiSlot()
{
    if(verifiMD5())
    {
        //qDebug() << "The and MD5Bytes are equal.";
        unverifiedOvertime = 0;
    }else
    {
        qWarning() << "VERIFICATION FAILED.";
        unverifiedOvertime += 1;
        if(unverifiedOvertime > 5)
        {
            //qWarning() << "Unauthorized device exceeding verification limit";
            emit unauthorized();
        }
    }

    QRandomGenerator *generator = QRandomGenerator::global();

    for (int i = 0; i < 16; ++i) {
        Last_randomBytes[i] = generator->bounded(256); // 生成0到255之间的随机数
    }
    protocol_MD5_send(Last_randomBytes);

}

void FloorSerial::openPort(const QString &portName, const int baudRate)
{
    LogDebug << "Atemptting to openPort";
    if (serial_) {
        emit responce("Open","串口已经打开");
        LogDebug << "Serial has open now return";
        return;
    }
    serial_ = new QSerialPort(this);
    serial_->setPortName(portName);
    serial_->setBaudRate(baudRate);

    if (!serial_->open(QIODevice::ReadWrite)) {

        QString  detail_temp = "Failed to open serial port because :" +serial_->errorString();
        LogError << detail_temp ;
        emit responce("Fail",detail_temp);
        return;
    }

    LogInfo << "Serial port initialized:" << portName_;
    connect(&workerThread, &QThread::finished, serial_, &QObject::deleteLater);
    portName_ = portName;
    baudRate_ = baudRate;
    LogDebug << "SerialPort created for port:" << portName_ << "with baud rate:" << baudRate;
    connect(serial_, &QSerialPort::readyRead, this, &FloorSerial::readDateCallBack);
    if(!serial_->isOpen())
    {
        LogError << "Serial port fail";
        emit responce("Fail","串口无法打开");
        return;
    }
    LogDebug << "Serial open successful";

    startVerifi();
    emit responce("Open","串口成功打开");
    emit openSerialFinish();

}

void FloorSerial::closePort()
{
    LogDebug << "Attempting to closePort";
    emit serialPortModelChanged();
    QThread::sleep(1);
    if (serial_) {
        serial_->close();
        if(serial_->isOpen())
        {

            delete serial_;
            serial_ = nullptr;

        }else
        {
            LogDebug << "closePort serial_->isOpen() is fail ";
            delete serial_;
            serial_ = nullptr;
        }

    }
    emit responce("Close","串口成功关闭");
    LogDebug << "successful closePort";
}

void FloorSerial::writeDataAddHead(const QByteArray& data) {
    if(!serial_)
    {
        LogError << "Failed to write data writeData is null";
        return ;
    }
    QByteArray modifiedCommand = QByteArray::fromHex("4154") + data + QByteArray::fromHex("0D0A");
    if (serial_->write(modifiedCommand) == -1) {
        LogError << "Failed to write data to serial port.";
        return;
    } else {
        serial_->waitForBytesWritten();
        return;
    }
}

void FloorSerial::readDateCallBack()
{
    QByteArray data = serial_->readAll();
    buffer_.append(data);
    //qDebug()   << "FloorSerial::readDateCallBack : " << buffer_.toHex().toUpper();;
    while (buffer_.size() >= 6) {
        if(buffer_.size() > 2048)
        {
            buffer_.clear(); // 没有找到起始字节，清空缓冲区
            return;
        }
        // 查找起始字节
        int start_index = buffer_.indexOf("\x55\xAA");
        if (start_index == -1 && buffer_.size() > 1024) {
            buffer_.clear(); // 未找到起始字节时清空缓冲区
            return;
        }

        // 检查起始字节是否在缓冲区的开头，如果不是，移除起始字节之前的数据
        if (start_index > 0) {
            buffer_.remove(0, start_index);
        }

        // 检查缓冲区中的数据长度是否足够解析出数据长度字段
        if (buffer_.size() < 6) {
            return; // 数据不足，等待更多数据
        }

        // 解析数据长度
        uint8_t data_length = static_cast<uint8_t>(buffer_[3]);

        // 数据帧的总长度为起始字节（2字节）+ 功能位（1字节）+ 数据长度（1字节）+ ID（1字节）+ 数据长度个字节 + 校验和（1字节）
        int frame_length = data_length;

        // 检查缓冲区中的数据长度是否足够解析出完整的数据帧
        if (buffer_.size() < frame_length) {
            return; // 数据不足，等待更多数据
        }

        // 解析功能位
        uint8_t function = static_cast<uint8_t>(buffer_[2]);

        // 解析数据
        QByteArray data = buffer_.mid(4, data_length - 1); // 数据字段

        // 校验和检查
        uint8_t received_checksum = static_cast<uint8_t>(buffer_[frame_length - 1]);
        uint8_t calculated_checksum = check_sum(0, reinterpret_cast<uint8_t*>(buffer_.data()), frame_length - 1);
        if (received_checksum != calculated_checksum) {
            qWarning() << "Checksum mismatch";
            buffer_.remove(0, 2); // 移除起始字节，然后继续检查
            continue;
        }
        buffer_.remove(0, frame_length); // 移除已处理的数据帧
        if(function==0x03)
        {
            revMD5 = data.mid(0, 16); // 拷贝data的前16个字节到revMD5中
            // LogDebug << "revMD5.size()" << revMD5.size();
        }else if(function == 0x04)
        {
            isMotorcallback = true;
            qDebug() << "get 0x04 callBack";
        }
        // qDebug() << "Function:" << QString::number(function, 16).rightJustified(2, '0').toUpper();
        // qDebug() << "Data:" << data.toHex().toUpper();
    }
}

void FloorSerial::controlFan(int id, float speed) {
    //startVerifiSlot();openSerialFinish
    if (id < 1 || id > 2 || speed < -1.0 || speed > 1.0) {
        LogError << "Invalid fan control parameters.";
        return;
    }
    if (protocol_data_send(1, id, speed) != 0) {
        LogError << "Failed to send fan control data.";
    } else {
        LogDebug << "Fan control data sent for ID:" << id << " Speed:" << speed;
    }
}

void FloorSerial::controlLight(int id, float brightness) {
    if (id < 1 || id > 4 || brightness < 0.0 || brightness > 1.0) {
        LogError << "Invalid light control parameters.";
        return;
    }
    if (protocol_data_send(2, id, brightness) != 0) {
        LogError << "Failed to send light control data.";
    } else {
        LogDebug << "Light control data sent for ID:" << id << " Brightness:" << brightness;
    }
}

void FloorSerial::autoRetrybyCall(uint8_t function, uint8_t id, float value, int maxRetries)
{

    protocol_data_send(function, id, value); // Send the initial data
    int *retryCount = new int(1); // Initialize retry counter

    QTimer *timer = new QTimer(this);
    timer->setInterval(10); // Set the interval (e.g., milliseconds)

    connect(timer, &QTimer::timeout, this, [=]() mutable {
        if (isMotorcallback || *retryCount >= maxRetries) {
            // Stop retries if callback received or max retries reached
            timer->stop();
            timer->deleteLater();
            delete retryCount;
        } else {
            qWarning() << "Fail autoRetrybyCall an retry protocol_data_send :" << *retryCount;
            protocol_data_send(function, id, value); // Resend data
            (*retryCount)++; // Increment retry counter
        }
    });

    timer->start(); // Start the timer
}

void FloorSerial::startMotor(float speed)
{
    autoRetrybyCall(5, 1, speed, 3);

}

void FloorSerial::stopMotor()
{
     autoRetrybyCall(5, 0, 0, 3);
}


void FloorSerial::replenishmentTrigge(float speed, int time)
{
    if (isProcessing) {
        LogDebug << "Replenishment already in progress, ignoring new call.";
        return;
    }

    isProcessing = true;  // 设置标志位
    if (protocol_data_send(5, 1, speed) != 0) {
        LogError << "Failed to send replenishmentTrigge data.";
        isProcessing = false;  // 重置标志位
    } else {
        LogDebug << "replenishmentTrigge sent for speed:" << speed << " time:" << time;
        QTimer::singleShot(time, [this]() {
            isMotorcallback =false;
            autoRetrybyCall(5, 0, 0, 3);
            isProcessing = false;  // 在autoRetrybyCall完成后重置标志位
        });
    }
}

void FloorSerial::holdserial() {
    if (protocol_data_send(4, 0, 0) != 0) {
        LogError << "Failed to send light control data.";
    }
}

void FloorSerial::valueTableLoad()
{
    LogDebug << "Attempting to FloorSerial::valueTableLoad ";
    m_mainlight = ParamValue.getParameter<float>("floor","mainlight");
    QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 1), Q_ARG(float, m_mainlight));
    QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 4), Q_ARG(float, m_mainlight));
    emit mainlightChanged();

    m_leftlight = ParamValue.getParameter<float>("floor", "leftlight");
    QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 2), Q_ARG(float, m_leftlight));
    emit leftlightChanged();

    m_rightlight = ParamValue.getParameter<float>("floor", "rightlight");
    QMetaObject::invokeMethod(this, "controlLight", Q_ARG(int, 3), Q_ARG(float, m_rightlight));
    emit rightlightChanged();

    m_fan1 = ParamValue.getParameter<float>("floor", "fan1");
    QMetaObject::invokeMethod(this, "controlFan", Q_ARG(int, 1), Q_ARG(float, m_fan1));
    emit fan1Changed();

    m_fan2 = ParamValue.getParameter<float>("floor", "fan2");
    QMetaObject::invokeMethod(this, "controlFan", Q_ARG(int, 2), Q_ARG(float, m_fan2));
    emit fan2Changed();
}


void FloorSerial::initSetting()
{
    setmainlight(ParamValue.getParameter<float>("floor","mainlight"));
    setleftlight(ParamValue.getParameter<float>("floor","leftlight"));
    setrightlight(ParamValue.getParameter<float>("floor","rightlight"));
    setfan1(ParamValue.getParameter<float>("floor","fan1"));
    setfan2(ParamValue.getParameter<float>("floor","fan2"));
}

int FloorSerial::protocol_data_send(uint8_t function, uint8_t id, float value) {
    uint8_t frame[10];
    uint8_t checksum = 0;

    frame[0] = 0x55;
    frame[1] = 0xAA;
    frame[2] = function;
    frame[3] = 0x0A;  // 数据长度
    frame[4] = id;
    std::memcpy(&frame[5], &value, sizeof(float));
    checksum = check_sum(0, frame, 9);
    frame[9] = checksum;

    if (serial_ && serial_->isOpen()) {
        if (serial_->write(reinterpret_cast<char*>(frame), 10) == -1) {
            LogError << "Failed to write data to serial port.";
            return -1; // 发送失败
        } else {
            serial_->waitForBytesWritten();
            return 0; // 发送成功
        }
    } else {
        LogError << "Serial port not open.";
        return -1;
    }
}

int FloorSerial::protocol_MD5_send(uint8_t *value)
{
    uint8_t frame[21];
    uint8_t checksum = 0;

    frame[0] = 0x55;
    frame[1] = 0xAA;
    frame[2] = 0x03;
    frame[3] = 21;  // 数据长度
    std::memcpy(&frame[4], value, 16);
    checksum = check_sum(0, frame, 20);
    frame[20] = checksum;

    // QByteArray byteArray(reinterpret_cast<const char*>(frame), sizeof(frame));
    // qDebug() << "Frame data:" << byteArray.toHex();

    if (serial_ && serial_->isOpen()) {
        if (serial_->write(reinterpret_cast<char*>(frame), 21) == -1) {
            LogError << "Failed to write data to serial port.";
            return -1; // 发送失败
        } else {
            serial_->waitForBytesWritten();
            return 0; // 发送成功
        }
    } else {
        LogError << "Serial port not open.";
        return -1;
    }
}

void FloorSerial::writeData(const QByteArray& data) {
    if(!serial_)
    {
        LogError << "Failed to write data writeData is null";
        return ;
    }
    if (serial_->write(data) == -1) {
        LogError << "Failed to write data to serial port.";
        return;
    } else {
        serial_->waitForBytesWritten();
        return;
    }
}

uint8_t FloorSerial::check_sum(uint8_t init, uint8_t *ptr, uint8_t len) {
    uint8_t sum = init;
    while (len--) {
        sum += *ptr++;
    }
    return sum;
}


